package org.tigris.atlas.examples.persist;

import java.util.Iterator;
import java.util.Set;

import junit.framework.TestCase;

import org.tigris.atlas.examples.service.OneToManyParentServiceResponse;
import org.tigris.atlas.examples.service.delegate.EntityMaintenanceServiceDelegate;
import org.tigris.atlas.examples.service.delegate.ServiceDelegateFactory;
import org.tigris.atlas.examples.transfer.OneToManyChild;
import org.tigris.atlas.examples.transfer.OneToManyChildPK;
import org.tigris.atlas.examples.transfer.OneToManyParent;
import org.tigris.atlas.examples.transfer.OneToManyParentPK;
import org.tigris.atlas.examples.transfer.TransferObjectFactory;

public class TestOneToManyRelation extends TestCase {
	
	EntityMaintenanceServiceDelegate delegate;

	protected void setUp() throws Exception {
		delegate = ServiceDelegateFactory.createEntityMaintenanceServiceDelegate();
		super.setUp();
	}
	
	protected void tearDown() throws Exception {
		super.tearDown();
		delegate = null;
	}
	
	public void testParentOnlyCreation() {
		OneToManyParent parent = TransferObjectFactory.createOneToManyParent();
		String value = "parentOnlyCreation";
		parent.setStringExample(value);
		
		OneToManyParentServiceResponse response = delegate.save(parent);
		assertFalse("no errors should exist!", response.getMessages().hasErrorMessages());
		parent = response.getOneToManyParent();
		
		String id = getAndVerifyId(parent);
		
		OneToManyParentPK pk = TransferObjectFactory.createOneToManyParentPK();		
		pk.setId(id);
		OneToManyParent reselect = delegate.findByPrimaryKey(pk).getOneToManyParent();
		
		//ensure that save was successful:
		verifyParentRetrieval(reselect);
	}
	
	public void testParentWithSingleChildCreation() {
		OneToManyParent parent = TransferObjectFactory.createOneToManyParent();
		String value = "parentWithSingleChildCreation";
		parent.setStringExample(value);
		
		OneToManyChild child0 = TransferObjectFactory.createOneToManyChild();
		String child0Value = "child0Value";
		child0.setStringExample(child0Value);
		
		parent.addOneToManyChild(child0);
		
		OneToManyParentServiceResponse response = delegate.save(parent);
		assertFalse("no errors should exist!", response.getMessages().hasErrorMessages());
		parent = response.getOneToManyParent();
		
		String id = getAndVerifyId(parent);
				
		OneToManyParentPK pk = TransferObjectFactory.createOneToManyParentPK();		
		pk.setId(id);
		OneToManyParent reselect = delegate.findByPrimaryKey(pk).getOneToManyParent();
		
		//ensure that save was successful:
		verifyParentRetrieval(reselect);
		Set childSet = verifySetExists(reselect);
		OneToManyChild reSelectedChild = verifySetSize(childSet, 1);
		verifyChildExists(reSelectedChild);
		verifyCorrectParent(reselect, reSelectedChild);
	}
	
	public void testParentWithMutlipleChildCreation() {
		OneToManyParent parent = TransferObjectFactory.createOneToManyParent();
		String value = "parentWithMultipleChildCreation";
		parent.setStringExample(value);
		
		OneToManyChild child0 = TransferObjectFactory.createOneToManyChild();
		String child0Value = "child0Value";
		child0.setStringExample(child0Value);
		OneToManyChild child1 = TransferObjectFactory.createOneToManyChild();
		String child1Value = "child1Value";
		child1.setStringExample(child1Value);
		OneToManyChild child2 = TransferObjectFactory.createOneToManyChild();
		String child2Value = "child2Value";
		child2.setStringExample(child2Value);		
		
		parent.addOneToManyChild(child0);
		parent.addOneToManyChild(child1);
		parent.addOneToManyChild(child2);
		
		OneToManyParentServiceResponse response = delegate.save(parent);
		assertFalse("no errors should exist!", response.getMessages().hasErrorMessages());
		parent = response.getOneToManyParent();
		
		String id = getAndVerifyId(parent);
		
		OneToManyParentPK pk = TransferObjectFactory.createOneToManyParentPK();		
		pk.setId(id);
		OneToManyParent reselect = delegate.findByPrimaryKey(pk).getOneToManyParent();
		
		//ensure that save was successful:
		verifyParentRetrieval(reselect);
		Set childSet = verifySetExists(reselect);
		verifySetSize(childSet, 3);
		OneToManyChild reSelectedChild;
		Iterator setIterator = childSet.iterator();
		while (setIterator.hasNext()) {
			reSelectedChild = (OneToManyChild)setIterator.next();
			verifyChildExists(reSelectedChild);
			verifyCorrectParent(reselect, reSelectedChild);
		}
		
	}	
	
	public void testAddingChildViaUpdate() {
		OneToManyParent parent = TransferObjectFactory.createOneToManyParent();
		String value = "parentWithMultipleChildCreation";
		parent.setStringExample(value);
		
		OneToManyParentServiceResponse response = delegate.save(parent);
		assertFalse("no errors should exist!", response.getMessages().hasErrorMessages());
		parent = response.getOneToManyParent();
		
		OneToManyChild child0 = TransferObjectFactory.createOneToManyChild();
		String child0Value = "child0Value";
		child0.setStringExample(child0Value);			
		parent.addOneToManyChild(child0);

		response = delegate.save(parent);
		assertFalse("no errors should exist!", response.getMessages().hasErrorMessages());
		parent = response.getOneToManyParent();
		
		String id = getAndVerifyId(parent);
		OneToManyParentPK pk = TransferObjectFactory.createOneToManyParentPK();		
		pk.setId(id);
		OneToManyParent reselect = delegate.findByPrimaryKey(pk).getOneToManyParent();
		
		//ensure that save was successful:
		verifyParentRetrieval(reselect);
		Set childSet = verifySetExists(reselect);
		verifySetSize(childSet, 1);
		OneToManyChild reSelectedChild = verifySetSize(childSet, 1);
		verifyChildExists(reSelectedChild);
		verifyCorrectParent(reselect, reSelectedChild);
		
	}
	
	public void testRemovingChildViaUpdate() {
		OneToManyParent parent = TransferObjectFactory.createOneToManyParent();
		String value = "parentWithMultipleChildCreation";
		parent.setStringExample(value);
		
		OneToManyChild child0 = TransferObjectFactory.createOneToManyChild();
		String child0Value = "child0Value";
		child0.setStringExample(child0Value);
		OneToManyChild child1 = TransferObjectFactory.createOneToManyChild();
		String child1Value = "child1Value";
		child1.setStringExample(child1Value);
		OneToManyChild child2 = TransferObjectFactory.createOneToManyChild();
		String child2Value = "child2Value";
		child2.setStringExample(child2Value);
		
		parent.addOneToManyChild(child0);
		parent.addOneToManyChild(child1);
		parent.addOneToManyChild(child2);
		
		OneToManyParentServiceResponse response = delegate.save(parent);
		assertFalse("no errors should exist!", response.getMessages().hasErrorMessages());
		parent = response.getOneToManyParent();		
		
		String id = getAndVerifyId(parent);
		
		//remove a child:
		OneToManyChild childToRemove = (OneToManyChild)parent.getOneToManyChilds().iterator().next();
		verifySetSize(parent.getOneToManyChilds(), 3);		
		parent.removeOneToManyChild(childToRemove);
		verifySetSize(parent.getOneToManyChilds(), 2);
		response = delegate.save(parent);
		assertFalse("no errors should exist!", response.getMessages().hasErrorMessages());
		parent = response.getOneToManyParent();
		
		OneToManyParentPK pk2 = TransferObjectFactory.createOneToManyParentPK();		
		pk2.setId(id);
		OneToManyParent reselect = delegate.findByPrimaryKey(pk2).getOneToManyParent();
		
		//ensure that save was successful:
		verifyParentRetrieval(reselect);
		Set childSet = verifySetExists(reselect);
		verifySetSize(childSet, 2);
		OneToManyChild reSelectedChild;
		Iterator setIterator = childSet.iterator();
		while (setIterator.hasNext()) {
			reSelectedChild = (OneToManyChild)setIterator.next();
			verifyChildExists(reSelectedChild);
			verifyCorrectParent(reselect, reSelectedChild);
		}
		
	}
	
	public void testChildUpdate() {
		OneToManyParent parent = TransferObjectFactory.createOneToManyParent();
		String value = "parentWithSingleChildCreation";
		parent.setStringExample(value);
		
		OneToManyChild child0 = TransferObjectFactory.createOneToManyChild();
		String child0Value = "child0Value";
		child0.setStringExample(child0Value);
		
		parent.addOneToManyChild(child0);
		
		OneToManyParentServiceResponse response = delegate.save(parent);
		assertFalse("no errors should exist!", response.getMessages().hasErrorMessages());
		parent = response.getOneToManyParent();
		
		//update child:
		OneToManyChild updatedChild = (OneToManyChild)parent.getOneToManyChilds().iterator().next();
		Integer updatedValue = new Integer(1001);
		updatedChild.setIntegerExample(updatedValue);
		response = delegate.save(parent);
		assertFalse("no errors should exist!", response.getMessages().hasErrorMessages());
		parent = response.getOneToManyParent();
		
		String id = getAndVerifyId(parent);
		
		OneToManyParentPK pk = TransferObjectFactory.createOneToManyParentPK();		
		pk.setId(id);
		OneToManyParent reselect = delegate.findByPrimaryKey(pk).getOneToManyParent();
		
		//ensure that save was successful:
		verifyParentRetrieval(reselect);
		Set childSet = verifySetExists(reselect);
		OneToManyChild reSelectedChild = verifySetSize(childSet, 1);
		verifyChildExists(reSelectedChild);
		Integer reselectedValue = reSelectedChild.getIntegerExample();
		assertEquals("Update value did not persist!", updatedValue, reselectedValue);
		verifyCorrectParent(reselect, reSelectedChild);
		
	}	
	
	public void testCascadingDelete() {
		OneToManyParent parent = TransferObjectFactory.createOneToManyParent();
		String value = "parentWithSingleChildCreation";
		parent.setStringExample(value);
		
		OneToManyChild child0 = TransferObjectFactory.createOneToManyChild();
		String child0Value = "child0Value";
		child0.setStringExample(child0Value);
		OneToManyChild child1 = TransferObjectFactory.createOneToManyChild();
		String child1Value = "child1Value";
		child1.setStringExample(child1Value);
		
		parent.addOneToManyChild(child0);
		parent.addOneToManyChild(child1);
		
		OneToManyParentServiceResponse response = delegate.save(parent);
		assertFalse("no errors should exist!", response.getMessages().hasErrorMessages());
		parent = response.getOneToManyParent();
		
		Set childSet = parent.getOneToManyChilds();
		
		//delete parent:
		delegate.delete(parent.getOneToManyParentPK());
		
		OneToManyChild child;
		Iterator i = childSet.iterator();
		while (i.hasNext()) {
			child = (OneToManyChild)i.next();			
			child = delegate.findByPrimaryKey((OneToManyChildPK)child.getKey()).getOneToManyChild();
			assertNull("Child record not deleted by parent!", child);
		}
		
	}
		
	
	//////////////////////////////////////////////////////////////
	// Helper methods:
	//////////////////////////////////////////////////////////////

	private void verifyParentRetrieval(OneToManyParent reselect) {
		assertNotNull("Could not find object", reselect);
	}

	private String getAndVerifyId(OneToManyParent parent) {
		String id = parent.getId();
		assertNotNull("No id value was assigned!", id);
		return id;
	}	
	
	private void verifyCorrectParent(OneToManyParent reselect, OneToManyChild reSelectedChild) {
		OneToManyParent childParent = reSelectedChild.getOneToManyParent();
		assertEquals("Inconsistent parents!", childParent.getId(), reselect.getId());
	}

	private void verifyChildExists(OneToManyChild reSelectedChild) {
		assertNotNull("Bad child record", reSelectedChild);
	}

	private Set verifySetExists(OneToManyParent reselect) {
		Set childSet = reselect.getOneToManyChilds();
		assertNotNull("No child set exists!", childSet);
		return childSet;
	}

	private OneToManyChild verifySetSize(Set childSet, int expectedSize) {
		int setSize = childSet.size();
		assertEquals("Incorrect set size!", expectedSize, setSize);
		OneToManyChild reSelectedChild = (OneToManyChild)childSet.iterator().next();
		return reSelectedChild;
	}	
	
}
